package ingress

import (
	"errors"
	"fmt"
	"math"
	"net/http"
	"net/http/httptest"
	"os"
	"path/filepath"
	"strings"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	ptypes "github.com/traefik/paerser/types"
	"github.com/traefik/traefik/v3/pkg/config/dynamic"
	traefikhttp "github.com/traefik/traefik/v3/pkg/muxer/http"
	otypes "github.com/traefik/traefik/v3/pkg/observability/types"
	"github.com/traefik/traefik/v3/pkg/provider"
	"github.com/traefik/traefik/v3/pkg/provider/kubernetes/k8s"
	"github.com/traefik/traefik/v3/pkg/tls"
	"github.com/traefik/traefik/v3/pkg/types"
	corev1 "k8s.io/api/core/v1"
	netv1 "k8s.io/api/networking/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	kubefake "k8s.io/client-go/kubernetes/fake"
)

var _ provider.Provider = (*Provider)(nil)

func pointer[T any](v T) *T { return &v }

func TestLoadConfigurationFromIngresses(t *testing.T) {
	testCases := []struct {
		desc                         string
		ingressClass                 string
		expected                     *dynamic.Configuration
		allowEmptyServices           bool
		disableIngressClassLookup    bool
		disableClusterScopeResources bool
		defaultRuleSyntax            string
		strictPrefixMatching         bool
	}{
		{
			desc: "Empty ingresses",
			expected: &dynamic.Configuration{
				HTTP: &dynamic.HTTPConfiguration{
					Routers:     map[string]*dynamic.Router{},
					Middlewares: map[string]*dynamic.Middleware{},
					Services:    map[string]*dynamic.Service{},
				},
			},
		},
		{
			desc: "Ingress one rule host only",
			expected: &dynamic.Configuration{
				HTTP: &dynamic.HTTPConfiguration{
					Routers:     map[string]*dynamic.Router{},
					Middlewares: map[string]*dynamic.Middleware{},
					Services:    map[string]*dynamic.Service{},
				},
			},
		},
		{
			desc: "Ingress with a basic rule on one path",
			expected: &dynamic.Configuration{
				HTTP: &dynamic.HTTPConfiguration{
					Middlewares: map[string]*dynamic.Middleware{},
					Routers: map[string]*dynamic.Router{
						"testing-bar": {
							Rule:    "PathPrefix(`/bar`)",
							Service: "testing-service1-80",
						},
					},
					Services: map[string]*dynamic.Service{
						"testing-service1-80": {
							LoadBalancer: &dynamic.ServersLoadBalancer{
								Strategy:       dynamic.BalancerStrategyWRR,
								PassHostHeader: pointer(true),
								ResponseForwarding: &dynamic.ResponseForwarding{
									FlushInterval: ptypes.Duration(100 * time.Millisecond),
								},
								Servers: []dynamic.Server{
									{
										URL: "http://10.10.0.1:8080",
									},
									{
										URL: "http://10.21.0.1:8080",
									},
								},
							},
						},
					},
				},
			},
		},
		{
			desc: "Ingress with annotations",
			expected: &dynamic.Configuration{
				HTTP: &dynamic.HTTPConfiguration{
					Middlewares: map[string]*dynamic.Middleware{},
					Routers: map[string]*dynamic.Router{
						"testing-bar": {
							Rule:        "Path(`/bar`)",
							EntryPoints: []string{"ep1", "ep2"},
							Service:     "testing-service1-80",
							Middlewares: []string{"md1", "md2"},
							Priority:    42,
							RuleSyntax:  "v2",
							TLS: &dynamic.RouterTLSConfig{
								CertResolver: "foobar",
								Domains: []types.Domain{
									{
										Main: "domain.com",
										SANs: []string{"one.domain.com", "two.domain.com"},
									},
									{
										Main: "example.com",
										SANs: []string{"one.example.com", "two.example.com"},
									},
								},
								Options: "foobar",
							},
							Observability: &dynamic.RouterObservabilityConfig{
								AccessLogs:     pointer(true),
								Tracing:        pointer(true),
								Metrics:        pointer(true),
								TraceVerbosity: otypes.MinimalVerbosity,
							},
						},
					},
					Services: map[string]*dynamic.Service{
						"testing-service1-80": {
							LoadBalancer: &dynamic.ServersLoadBalancer{
								Strategy:       dynamic.BalancerStrategyWRR,
								PassHostHeader: pointer(true),
								ResponseForwarding: &dynamic.ResponseForwarding{
									FlushInterval: ptypes.Duration(100 * time.Millisecond),
								},
								Sticky: &dynamic.Sticky{
									Cookie: &dynamic.Cookie{
										Name:     "foobar",
										Secure:   true,
										HTTPOnly: true,
										Path:     pointer("/"),
									},
								},
								Servers: []dynamic.Server{
									{
										URL: "protocol://10.10.0.1:8080",
									},
									{
										URL: "protocol://10.21.0.1:8080",
									},
								},
								ServersTransport: "foobar@file",
							},
						},
					},
				},
			},
		},
		{
			desc: "Ingress with two different rules with one path",
			expected: &dynamic.Configuration{
				HTTP: &dynamic.HTTPConfiguration{
					Middlewares: map[string]*dynamic.Middleware{},
					Routers: map[string]*dynamic.Router{
						"testing-bar": {
							Rule:    "PathPrefix(`/bar`)",
							Service: "testing-service1-80",
						},
						"testing-foo": {
							Rule:    "PathPrefix(`/foo`)",
							Service: "testing-service1-80",
						},
					},
					Services: map[string]*dynamic.Service{
						"testing-service1-80": {
							LoadBalancer: &dynamic.ServersLoadBalancer{
								Strategy:       dynamic.BalancerStrategyWRR,
								PassHostHeader: pointer(true),
								ResponseForwarding: &dynamic.ResponseForwarding{
									FlushInterval: ptypes.Duration(100 * time.Millisecond),
								},
								Servers: []dynamic.Server{
									{
										URL: "http://10.10.0.1:8080",
									},
									{
										URL: "http://10.21.0.1:8080",
									},
								},
							},
						},
					},
				},
			},
		},
		{
			desc: "Ingress with conflicting routers on host",
			expected: &dynamic.Configuration{
				HTTP: &dynamic.HTTPConfiguration{
					Middlewares: map[string]*dynamic.Middleware{},
					Routers: map[string]*dynamic.Router{
						"testing-bar-bar-aba9a7d00e9b06a78e16": {
							Rule:    "HostRegexp(`^[a-zA-Z0-9-]+\\.bar$`) && PathPrefix(`/bar`)",
							Service: "testing-service1-80",
						},
						"testing-bar-bar-636bf36c00fedaab3d44": {
							Rule:    "Host(`bar`) && PathPrefix(`/bar`)",
							Service: "testing-service1-80",
						},
					},
					Services: map[string]*dynamic.Service{
						"testing-service1-80": {
							LoadBalancer: &dynamic.ServersLoadBalancer{
								Strategy:       dynamic.BalancerStrategyWRR,
								PassHostHeader: pointer(true),
								ResponseForwarding: &dynamic.ResponseForwarding{
									FlushInterval: ptypes.Duration(100 * time.Millisecond),
								},
								Servers: []dynamic.Server{
									{
										URL: "http://10.10.0.1:8080",
									},
									{
										URL: "http://10.21.0.1:8080",
									},
								},
							},
						},
					},
				},
			},
		},
		{
			desc: "Ingress with conflicting routers on path",
			expected: &dynamic.Configuration{
				HTTP: &dynamic.HTTPConfiguration{
					Middlewares: map[string]*dynamic.Middleware{},
					Routers: map[string]*dynamic.Router{
						"testing-foo-bar-d0b30949e54d6a7515ca": {
							Rule:    "PathPrefix(`/foo/bar`)",
							Service: "testing-service1-80",
						},
						"testing-foo-bar-dcd54bae39a6d7557f48": {
							Rule:    "PathPrefix(`/foo-bar`)",
							Service: "testing-service1-80",
						},
					},
					Services: map[string]*dynamic.Service{
						"testing-service1-80": {
							LoadBalancer: &dynamic.ServersLoadBalancer{
								Strategy:       dynamic.BalancerStrategyWRR,
								PassHostHeader: pointer(true),
								ResponseForwarding: &dynamic.ResponseForwarding{
									FlushInterval: ptypes.Duration(100 * time.Millisecond),
								},
								Servers: []dynamic.Server{
									{
										URL: "http://10.10.0.1:8080",
									},
									{
										URL: "http://10.21.0.1:8080",
									},
								},
							},
						},
					},
				},
			},
		},
		{
			desc: "Ingress one rule with two paths",
			expected: &dynamic.Configuration{
				HTTP: &dynamic.HTTPConfiguration{
					Middlewares: map[string]*dynamic.Middleware{},
					Routers: map[string]*dynamic.Router{
						"testing-bar": {
							Rule:    "PathPrefix(`/bar`)",
							Service: "testing-service1-80",
						},
						"testing-foo": {
							Rule:    "PathPrefix(`/foo`)",
							Service: "testing-service1-80",
						},
					},
					Services: map[string]*dynamic.Service{
						"testing-service1-80": {
							LoadBalancer: &dynamic.ServersLoadBalancer{
								Strategy:       dynamic.BalancerStrategyWRR,
								PassHostHeader: pointer(true),
								ResponseForwarding: &dynamic.ResponseForwarding{
									FlushInterval: ptypes.Duration(100 * time.Millisecond),
								},
								Servers: []dynamic.Server{
									{
										URL: "http://10.10.0.1:8080",
									},
									{
										URL: "http://10.21.0.1:8080",
									},
								},
							},
						},
					},
				},
			},
		},
		{
			desc: "Ingress one rule with one path and one host",
			expected: &dynamic.Configuration{
				HTTP: &dynamic.HTTPConfiguration{
					Middlewares: map[string]*dynamic.Middleware{},
					Routers: map[string]*dynamic.Router{
						"testing-traefik-tchouk-bar": {
							Rule:    "Host(`traefik.tchouk`) && PathPrefix(`/bar`)",
							Service: "testing-service1-80",
						},
					},
					Services: map[string]*dynamic.Service{
						"testing-service1-80": {
							LoadBalancer: &dynamic.ServersLoadBalancer{
								Strategy:       dynamic.BalancerStrategyWRR,
								PassHostHeader: pointer(true),
								ResponseForwarding: &dynamic.ResponseForwarding{
									FlushInterval: ptypes.Duration(100 * time.Millisecond),
								},
								Servers: []dynamic.Server{
									{
										URL: "http://10.10.0.1:8080",
									},
									{
										URL: "http://10.21.0.1:8080",
									},
								},
							},
						},
					},
				},
			},
		},
		{
			desc: "Ingress with one host without path",
			expected: &dynamic.Configuration{
				HTTP: &dynamic.HTTPConfiguration{
					Middlewares: map[string]*dynamic.Middleware{},
					Routers: map[string]*dynamic.Router{
						"testing-example-com": {
							Rule:    "Host(`example.com`)",
							Service: "testing-example-com-80",
						},
					},
					Services: map[string]*dynamic.Service{
						"testing-example-com-80": {
							LoadBalancer: &dynamic.ServersLoadBalancer{
								Strategy:       dynamic.BalancerStrategyWRR,
								PassHostHeader: pointer(true),
								ResponseForwarding: &dynamic.ResponseForwarding{
									FlushInterval: ptypes.Duration(100 * time.Millisecond),
								},
								Servers: []dynamic.Server{
									{
										URL: "http://10.11.0.1:80",
									},
								},
							},
						},
					},
				},
			},
		},
		{
			desc: "Ingress one rule with one host and two paths",
			expected: &dynamic.Configuration{
				HTTP: &dynamic.HTTPConfiguration{
					Middlewares: map[string]*dynamic.Middleware{},
					Routers: map[string]*dynamic.Router{
						"testing-traefik-tchouk-bar": {
							Rule:    "Host(`traefik.tchouk`) && PathPrefix(`/bar`)",
							Service: "testing-service1-80",
						},
						"testing-traefik-tchouk-foo": {
							Rule:    "Host(`traefik.tchouk`) && PathPrefix(`/foo`)",
							Service: "testing-service1-80",
						},
					},
					Services: map[string]*dynamic.Service{
						"testing-service1-80": {
							LoadBalancer: &dynamic.ServersLoadBalancer{
								Strategy:       dynamic.BalancerStrategyWRR,
								PassHostHeader: pointer(true),
								ResponseForwarding: &dynamic.ResponseForwarding{
									FlushInterval: ptypes.Duration(100 * time.Millisecond),
								},
								Servers: []dynamic.Server{
									{
										URL: "http://10.10.0.1:8080",
									},
									{
										URL: "http://10.21.0.1:8080",
									},
								},
							},
						},
					},
				},
			},
		},
		{
			desc: "Ingress Two rules with one host and one path",
			expected: &dynamic.Configuration{
				HTTP: &dynamic.HTTPConfiguration{
					Middlewares: map[string]*dynamic.Middleware{},
					Routers: map[string]*dynamic.Router{
						"testing-traefik-tchouk-bar": {
							Rule:    "Host(`traefik.tchouk`) && PathPrefix(`/bar`)",
							Service: "testing-service1-80",
						},
						"testing-traefik-courgette-carotte": {
							Rule:    "Host(`traefik.courgette`) && PathPrefix(`/carotte`)",
							Service: "testing-service1-80",
						},
					},
					Services: map[string]*dynamic.Service{
						"testing-service1-80": {
							LoadBalancer: &dynamic.ServersLoadBalancer{
								Strategy:       dynamic.BalancerStrategyWRR,
								PassHostHeader: pointer(true),
								ResponseForwarding: &dynamic.ResponseForwarding{
									FlushInterval: ptypes.Duration(100 * time.Millisecond),
								},
								Servers: []dynamic.Server{
									{
										URL: "http://10.10.0.1:8080",
									},
									{
										URL: "http://10.21.0.1:8080",
									},
								},
							},
						},
					},
				},
			},
		},
		{
			desc: "Ingress with two services",
			expected: &dynamic.Configuration{
				HTTP: &dynamic.HTTPConfiguration{
					Middlewares: map[string]*dynamic.Middleware{},
					Routers: map[string]*dynamic.Router{
						"testing-traefik-tchouk-bar": {
							Rule:    "Host(`traefik.tchouk`) && PathPrefix(`/bar`)",
							Service: "testing-service1-80",
						},
						"testing-traefik-courgette-carotte": {
							Rule:    "Host(`traefik.courgette`) && PathPrefix(`/carotte`)",
							Service: "testing-service2-8082",
						},
					},
					Services: map[string]*dynamic.Service{
						"testing-service1-80": {
							LoadBalancer: &dynamic.ServersLoadBalancer{
								Strategy:       dynamic.BalancerStrategyWRR,
								PassHostHeader: pointer(true),
								ResponseForwarding: &dynamic.ResponseForwarding{
									FlushInterval: ptypes.Duration(100 * time.Millisecond),
								},
								Servers: []dynamic.Server{
									{
										URL: "http://10.10.0.1:8080",
									},
									{
										URL: "http://10.21.0.1:8080",
									},
								},
							},
						},
						"testing-service2-8082": {
							LoadBalancer: &dynamic.ServersLoadBalancer{
								Strategy:       dynamic.BalancerStrategyWRR,
								PassHostHeader: pointer(true),
								ResponseForwarding: &dynamic.ResponseForwarding{
									FlushInterval: ptypes.Duration(100 * time.Millisecond),
								},
								Servers: []dynamic.Server{
									{
										URL: "http://10.10.0.2:8080",
									},
									{
										URL: "http://10.21.0.2:8080",
									},
								},
							},
						},
					},
				},
			},
		},
		{
			desc:               "Ingress with one service without endpoints subset",
			allowEmptyServices: true,
			expected: &dynamic.Configuration{
				HTTP: &dynamic.HTTPConfiguration{
					Middlewares: map[string]*dynamic.Middleware{},
					Routers: map[string]*dynamic.Router{
						"testing-traefik-tchouk-bar": {
							Rule:    "Host(`traefik.tchouk`) && PathPrefix(`/bar`)",
							Service: "testing-service1-80",
						},
					},
					Services: map[string]*dynamic.Service{
						"testing-service1-80": {
							LoadBalancer: &dynamic.ServersLoadBalancer{
								Strategy:       dynamic.BalancerStrategyWRR,
								PassHostHeader: pointer(true),
								ResponseForwarding: &dynamic.ResponseForwarding{
									FlushInterval: ptypes.Duration(100 * time.Millisecond),
								},
							},
						},
					},
				},
			},
		},
		{
			desc:               "Ingress with backend resource",
			allowEmptyServices: true,
			expected: &dynamic.Configuration{
				HTTP: &dynamic.HTTPConfiguration{
					Middlewares: map[string]*dynamic.Middleware{},
					Routers:     map[string]*dynamic.Router{},
					Services:    map[string]*dynamic.Service{},
				},
			},
		},
		{
			desc:               "Ingress without backend",
			allowEmptyServices: true,
			expected: &dynamic.Configuration{
				HTTP: &dynamic.HTTPConfiguration{
					Middlewares: map[string]*dynamic.Middleware{},
					Routers:     map[string]*dynamic.Router{},
					Services:    map[string]*dynamic.Service{},
				},
			},
		},
		{
			desc: "Ingress with one service without endpoint",
			expected: &dynamic.Configuration{
				HTTP: &dynamic.HTTPConfiguration{
					Middlewares: map[string]*dynamic.Middleware{},
					Routers:     map[string]*dynamic.Router{},
					Services:    map[string]*dynamic.Service{},
				},
			},
		},
		{
			desc: "Single Service Ingress (without any rules)",
			expected: &dynamic.Configuration{
				HTTP: &dynamic.HTTPConfiguration{
					Middlewares: map[string]*dynamic.Middleware{},
					Routers: map[string]*dynamic.Router{
						"default-router": {
							Rule:       "PathPrefix(`/`)",
							RuleSyntax: "default",
							Service:    "default-backend",
							Priority:   math.MinInt32,
						},
					},
					Services: map[string]*dynamic.Service{
						"default-backend": {
							LoadBalancer: &dynamic.ServersLoadBalancer{
								Strategy:       dynamic.BalancerStrategyWRR,
								PassHostHeader: pointer(true),
								ResponseForwarding: &dynamic.ResponseForwarding{
									FlushInterval: ptypes.Duration(100 * time.Millisecond),
								},
								Servers: []dynamic.Server{
									{
										URL: "http://10.10.0.1:8080",
									},
									{
										URL: "http://10.21.0.1:8080",
									},
								},
							},
						},
					},
				},
			},
		},
		{
			desc: "Ingress with port value in backend and no pod replica",
			expected: &dynamic.Configuration{
				HTTP: &dynamic.HTTPConfiguration{
					Middlewares: map[string]*dynamic.Middleware{},
					Routers: map[string]*dynamic.Router{
						"testing-traefik-tchouk-bar": {
							Rule:    "Host(`traefik.tchouk`) && PathPrefix(`/bar`)",
							Service: "testing-service1-80",
						},
					},
					Services: map[string]*dynamic.Service{
						"testing-service1-80": {
							LoadBalancer: &dynamic.ServersLoadBalancer{
								Strategy:       dynamic.BalancerStrategyWRR,
								PassHostHeader: pointer(true),
								ResponseForwarding: &dynamic.ResponseForwarding{
									FlushInterval: ptypes.Duration(100 * time.Millisecond),
								},
								Servers: []dynamic.Server{
									{
										URL: "http://10.10.0.1:8089",
									},
									{
										URL: "http://10.21.0.1:8089",
									},
								},
							},
						},
					},
				},
			},
		},
		{
			desc: "Ingress with port name in backend and no pod replica",
			expected: &dynamic.Configuration{
				HTTP: &dynamic.HTTPConfiguration{
					Middlewares: map[string]*dynamic.Middleware{},
					Routers: map[string]*dynamic.Router{
						"testing-traefik-tchouk-bar": {
							Rule:    "Host(`traefik.tchouk`) && PathPrefix(`/bar`)",
							Service: "testing-service1-tchouk",
						},
					},
					Services: map[string]*dynamic.Service{
						"testing-service1-tchouk": {
							LoadBalancer: &dynamic.ServersLoadBalancer{
								Strategy:       dynamic.BalancerStrategyWRR,
								PassHostHeader: pointer(true),
								ResponseForwarding: &dynamic.ResponseForwarding{
									FlushInterval: ptypes.Duration(100 * time.Millisecond),
								},
								Servers: []dynamic.Server{
									{
										URL: "http://10.10.0.1:8089",
									},
									{
										URL: "http://10.21.0.1:8089",
									},
								},
							},
						},
					},
				},
			},
		},
		{
			desc: "Ingress with port name in backend and 2 pod replica",
			expected: &dynamic.Configuration{
				HTTP: &dynamic.HTTPConfiguration{
					Middlewares: map[string]*dynamic.Middleware{},
					Routers: map[string]*dynamic.Router{
						"testing-traefik-tchouk-bar": {
							Rule:    "Host(`traefik.tchouk`) && PathPrefix(`/bar`)",
							Service: "testing-service1-tchouk",
						},
					},
					Services: map[string]*dynamic.Service{
						"testing-service1-tchouk": {
							LoadBalancer: &dynamic.ServersLoadBalancer{
								Strategy:       dynamic.BalancerStrategyWRR,
								PassHostHeader: pointer(true),
								ResponseForwarding: &dynamic.ResponseForwarding{
									FlushInterval: ptypes.Duration(100 * time.Millisecond),
								},
								Servers: []dynamic.Server{
									{
										URL: "http://10.10.0.1:8089",
									},
									{
										URL: "http://10.10.0.2:8089",
									},
								},
							},
						},
					},
				},
			},
		},
		{
			desc: "Ingress with two paths using same service and different port name",
			expected: &dynamic.Configuration{
				HTTP: &dynamic.HTTPConfiguration{
					Middlewares: map[string]*dynamic.Middleware{},
					Routers: map[string]*dynamic.Router{
						"testing-traefik-tchouk-bar": {
							Rule:    "Host(`traefik.tchouk`) && PathPrefix(`/bar`)",
							Service: "testing-service1-tchouk",
						},
						"testing-traefik-tchouk-foo": {
							Rule:    "Host(`traefik.tchouk`) && PathPrefix(`/foo`)",
							Service: "testing-service1-carotte",
						},
					},
					Services: map[string]*dynamic.Service{
						"testing-service1-tchouk": {
							LoadBalancer: &dynamic.ServersLoadBalancer{
								Strategy:       dynamic.BalancerStrategyWRR,
								PassHostHeader: pointer(true),
								ResponseForwarding: &dynamic.ResponseForwarding{
									FlushInterval: ptypes.Duration(100 * time.Millisecond),
								},
								Servers: []dynamic.Server{
									{
										URL: "http://10.10.0.1:8089",
									},
									{
										URL: "http://10.10.0.2:8089",
									},
								},
							},
						},
						"testing-service1-carotte": {
							LoadBalancer: &dynamic.ServersLoadBalancer{
								Strategy:       dynamic.BalancerStrategyWRR,
								PassHostHeader: pointer(true),
								ResponseForwarding: &dynamic.ResponseForwarding{
									FlushInterval: ptypes.Duration(100 * time.Millisecond),
								},
								Servers: []dynamic.Server{
									{
										URL: "http://10.10.0.1:8090",
									},
									{
										URL: "http://10.10.0.2:8090",
									},
								},
							},
						},
					},
				},
			},
		},
		{
			desc: "Ingress with a named port matching subset of service pods",
			expected: &dynamic.Configuration{
				HTTP: &dynamic.HTTPConfiguration{
					Middlewares: map[string]*dynamic.Middleware{},
					Routers: map[string]*dynamic.Router{
						"testing-traefik-tchouk-bar": {
							Rule:    "Host(`traefik.tchouk`) && PathPrefix(`/bar`)",
							Service: "testing-service1-tchouk",
						},
					},
					Services: map[string]*dynamic.Service{
						"testing-service1-tchouk": {
							LoadBalancer: &dynamic.ServersLoadBalancer{
								Strategy:       dynamic.BalancerStrategyWRR,
								PassHostHeader: pointer(true),
								ResponseForwarding: &dynamic.ResponseForwarding{
									FlushInterval: ptypes.Duration(100 * time.Millisecond),
								},
								Servers: []dynamic.Server{
									{
										URL: "http://10.10.0.1:8089",
									},
									{
										URL: "http://10.10.0.2:8089",
									},
								},
							},
						},
					},
				},
			},
		},
		{
			desc: "2 ingresses in different namespace with same service name",
			expected: &dynamic.Configuration{
				HTTP: &dynamic.HTTPConfiguration{
					Middlewares: map[string]*dynamic.Middleware{},
					Routers: map[string]*dynamic.Router{
						"testing-traefik-tchouk-bar": {
							Rule:    "Host(`traefik.tchouk`) && PathPrefix(`/bar`)",
							Service: "testing-service1-tchouk",
						},
						"toto-toto-traefik-tchouk-bar": {
							Rule:    "Host(`toto.traefik.tchouk`) && PathPrefix(`/bar`)",
							Service: "toto-service1-tchouk",
						},
					},
					Services: map[string]*dynamic.Service{
						"testing-service1-tchouk": {
							LoadBalancer: &dynamic.ServersLoadBalancer{
								Strategy:       dynamic.BalancerStrategyWRR,
								PassHostHeader: pointer(true),
								ResponseForwarding: &dynamic.ResponseForwarding{
									FlushInterval: ptypes.Duration(100 * time.Millisecond),
								},
								Servers: []dynamic.Server{
									{
										URL: "http://10.10.0.1:8089",
									},
									{
										URL: "http://10.10.0.2:8089",
									},
								},
							},
						},
						"toto-service1-tchouk": {
							LoadBalancer: &dynamic.ServersLoadBalancer{
								Strategy:       dynamic.BalancerStrategyWRR,
								PassHostHeader: pointer(true),
								ResponseForwarding: &dynamic.ResponseForwarding{
									FlushInterval: ptypes.Duration(100 * time.Millisecond),
								},
								Servers: []dynamic.Server{
									{
										URL: "http://10.11.0.1:8089",
									},
									{
										URL: "http://10.11.0.2:8089",
									},
								},
							},
						},
					},
				},
			},
		},
		{
			desc: "Ingress with unknown service port name",
			expected: &dynamic.Configuration{
				HTTP: &dynamic.HTTPConfiguration{
					Middlewares: map[string]*dynamic.Middleware{},
					Routers:     map[string]*dynamic.Router{},
					Services:    map[string]*dynamic.Service{},
				},
			},
		},
		{
			desc: "Ingress with unknown service port",
			expected: &dynamic.Configuration{
				HTTP: &dynamic.HTTPConfiguration{
					Middlewares: map[string]*dynamic.Middleware{},
					Routers:     map[string]*dynamic.Router{},
					Services:    map[string]*dynamic.Service{},
				},
			},
		},
		{
			desc: "Ingress with port invalid for one service",
			expected: &dynamic.Configuration{
				HTTP: &dynamic.HTTPConfiguration{
					Middlewares: map[string]*dynamic.Middleware{},
					Routers: map[string]*dynamic.Router{
						"testing-traefik-port-port": {
							Rule:    "Host(`traefik.port`) && PathPrefix(`/port`)",
							Service: "testing-service1-8080",
						},
					},
					Services: map[string]*dynamic.Service{
						"testing-service1-8080": {
							LoadBalancer: &dynamic.ServersLoadBalancer{
								Strategy:       dynamic.BalancerStrategyWRR,
								PassHostHeader: pointer(true),
								ResponseForwarding: &dynamic.ResponseForwarding{
									FlushInterval: ptypes.Duration(100 * time.Millisecond),
								},
								Servers: []dynamic.Server{
									{
										URL: "http://10.0.0.1:8080",
									},
								},
							},
						},
					},
				},
			},
		},
		{
			desc: "TLS support",
			expected: &dynamic.Configuration{
				HTTP: &dynamic.HTTPConfiguration{
					Middlewares: map[string]*dynamic.Middleware{},
					Routers: map[string]*dynamic.Router{
						"testing-example-com": {
							Rule:    "Host(`example.com`)",
							Service: "testing-example-com-80",
							TLS:     &dynamic.RouterTLSConfig{},
						},
					},
					Services: map[string]*dynamic.Service{
						"testing-example-com-80": {
							LoadBalancer: &dynamic.ServersLoadBalancer{
								Strategy:       dynamic.BalancerStrategyWRR,
								PassHostHeader: pointer(true),
								ResponseForwarding: &dynamic.ResponseForwarding{
									FlushInterval: ptypes.Duration(100 * time.Millisecond),
								},
								Servers: []dynamic.Server{
									{
										URL: "http://10.11.0.1:80",
									},
								},
							},
						},
					},
				},
				TLS: &dynamic.TLSConfiguration{
					Certificates: []*tls.CertAndStores{
						{
							Certificate: tls.Certificate{
								CertFile: types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
								KeyFile:  types.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"),
							},
						},
					},
				},
			},
		},
		{
			desc: "Ingress with a basic rule on one path with https (port == 443)",
			expected: &dynamic.Configuration{
				HTTP: &dynamic.HTTPConfiguration{
					Middlewares: map[string]*dynamic.Middleware{},
					Routers: map[string]*dynamic.Router{
						"testing-bar": {
							Rule:    "PathPrefix(`/bar`)",
							Service: "testing-service1-443",
						},
					},
					Services: map[string]*dynamic.Service{
						"testing-service1-443": {
							LoadBalancer: &dynamic.ServersLoadBalancer{
								Strategy:       dynamic.BalancerStrategyWRR,
								PassHostHeader: pointer(true),
								ResponseForwarding: &dynamic.ResponseForwarding{
									FlushInterval: ptypes.Duration(100 * time.Millisecond),
								},
								Servers: []dynamic.Server{
									{
										URL: "https://10.10.0.1:8443",
									},
									{
										URL: "https://10.21.0.1:8443",
									},
								},
							},
						},
					},
				},
			},
		},
		{
			desc: "Ingress with a basic rule on one path with https (portname == https)",
			expected: &dynamic.Configuration{
				HTTP: &dynamic.HTTPConfiguration{
					Middlewares: map[string]*dynamic.Middleware{},
					Routers: map[string]*dynamic.Router{
						"testing-bar": {
							Rule:    "PathPrefix(`/bar`)",
							Service: "testing-service1-8443",
						},
					},
					Services: map[string]*dynamic.Service{
						"testing-service1-8443": {
							LoadBalancer: &dynamic.ServersLoadBalancer{
								Strategy:       dynamic.BalancerStrategyWRR,
								PassHostHeader: pointer(true),
								ResponseForwarding: &dynamic.ResponseForwarding{
									FlushInterval: ptypes.Duration(100 * time.Millisecond),
								},
								Servers: []dynamic.Server{
									{
										URL: "https://10.10.0.1:8443",
									},
									{
										URL: "https://10.21.0.1:8443",
									},
								},
							},
						},
					},
				},
			},
		},
		{
			desc: "Ingress with a basic rule on one path with https (portname starts with https)",
			expected: &dynamic.Configuration{
				HTTP: &dynamic.HTTPConfiguration{
					Middlewares: map[string]*dynamic.Middleware{},

					Routers: map[string]*dynamic.Router{
						"testing-bar": {
							Rule:    "PathPrefix(`/bar`)",
							Service: "testing-service1-8443",
						},
					},
					Services: map[string]*dynamic.Service{
						"testing-service1-8443": {
							LoadBalancer: &dynamic.ServersLoadBalancer{
								Strategy:       dynamic.BalancerStrategyWRR,
								PassHostHeader: pointer(true),
								ResponseForwarding: &dynamic.ResponseForwarding{
									FlushInterval: ptypes.Duration(100 * time.Millisecond),
								},
								Servers: []dynamic.Server{
									{
										URL: "https://10.10.0.1:8443",
									},
									{
										URL: "https://10.21.0.1:8443",
									},
								},
							},
						},
					},
				},
			},
		},
		{
			desc: "Double Single Service Ingress",
			expected: &dynamic.Configuration{
				HTTP: &dynamic.HTTPConfiguration{
					Middlewares: map[string]*dynamic.Middleware{},
					Routers: map[string]*dynamic.Router{
						"default-router": {
							Rule:       "PathPrefix(`/`)",
							RuleSyntax: "default",
							Service:    "default-backend",
							Priority:   math.MinInt32,
						},
					},
					Services: map[string]*dynamic.Service{
						"default-backend": {
							LoadBalancer: &dynamic.ServersLoadBalancer{
								Strategy:       dynamic.BalancerStrategyWRR,
								PassHostHeader: pointer(true),
								ResponseForwarding: &dynamic.ResponseForwarding{
									FlushInterval: ptypes.Duration(100 * time.Millisecond),
								},
								Servers: []dynamic.Server{
									{
										URL: "http://10.30.0.1:8080",
									},
									{
										URL: "http://10.41.0.1:8080",
									},
								},
							},
						},
					},
				},
			},
		},
		{
			desc: "Ingress with default traefik ingressClass",
			expected: &dynamic.Configuration{
				HTTP: &dynamic.HTTPConfiguration{
					Middlewares: map[string]*dynamic.Middleware{},
					Routers: map[string]*dynamic.Router{
						"testing-bar": {
							Rule:    "PathPrefix(`/bar`)",
							Service: "testing-service1-80",
						},
					},
					Services: map[string]*dynamic.Service{
						"testing-service1-80": {
							LoadBalancer: &dynamic.ServersLoadBalancer{
								Strategy:       dynamic.BalancerStrategyWRR,
								PassHostHeader: pointer(true),
								ResponseForwarding: &dynamic.ResponseForwarding{
									FlushInterval: ptypes.Duration(100 * time.Millisecond),
								},
								Servers: []dynamic.Server{
									{
										URL: "http://10.10.0.1:8080",
									},
								},
							},
						},
					},
				},
			},
		},
		{
			desc: "Ingress without provider traefik ingressClass and unknown annotation",
			expected: &dynamic.Configuration{
				HTTP: &dynamic.HTTPConfiguration{
					Middlewares: map[string]*dynamic.Middleware{},
					Routers:     map[string]*dynamic.Router{},
					Services:    map[string]*dynamic.Service{},
				},
			},
		},
		{
			desc:         "Ingress with non matching provider traefik ingressClass and annotation",
			ingressClass: "tchouk",
			expected: &dynamic.Configuration{
				HTTP: &dynamic.HTTPConfiguration{
					Middlewares: map[string]*dynamic.Middleware{},
					Routers:     map[string]*dynamic.Router{},
					Services:    map[string]*dynamic.Service{},
				},
			},
		},
		{
			desc:         "Ingress with ingressClass without annotation",
			ingressClass: "tchouk",
			expected: &dynamic.Configuration{
				HTTP: &dynamic.HTTPConfiguration{
					Middlewares: map[string]*dynamic.Middleware{},
					Routers:     map[string]*dynamic.Router{},
					Services:    map[string]*dynamic.Service{},
				},
			},
		},
		{
			desc:         "Ingress with ingressClass without annotation",
			ingressClass: "toto",
			expected: &dynamic.Configuration{
				HTTP: &dynamic.HTTPConfiguration{
					Middlewares: map[string]*dynamic.Middleware{},
					Routers:     map[string]*dynamic.Router{},
					Services:    map[string]*dynamic.Service{},
				},
			},
		},
		{
			desc: "Ingress with wildcard host",
			expected: &dynamic.Configuration{
				HTTP: &dynamic.HTTPConfiguration{
					Middlewares: map[string]*dynamic.Middleware{},
					Routers: map[string]*dynamic.Router{
						"testing-foobar-com-bar": {
							Rule:    "HostRegexp(`^[a-zA-Z0-9-]+\\.foobar\\.com$`) && PathPrefix(`/bar`)",
							Service: "testing-service1-80",
						},
					},
					Services: map[string]*dynamic.Service{
						"testing-service1-80": {
							LoadBalancer: &dynamic.ServersLoadBalancer{
								Strategy:       dynamic.BalancerStrategyWRR,
								PassHostHeader: pointer(true),
								ResponseForwarding: &dynamic.ResponseForwarding{
									FlushInterval: ptypes.Duration(100 * time.Millisecond),
								},
								Servers: []dynamic.Server{
									{
										URL:    "http://10.10.0.1:8080",
										Scheme: "",
										Port:   "",
									},
								},
							},
						},
					},
				},
			},
		},
		{
			desc:              "Ingress with wildcard host syntax v2",
			defaultRuleSyntax: "v2",
			expected: &dynamic.Configuration{
				HTTP: &dynamic.HTTPConfiguration{
					Middlewares: map[string]*dynamic.Middleware{},
					Routers: map[string]*dynamic.Router{
						"testing-foobar-com-bar": {
							Rule:    "HostRegexp(`{subdomain:[a-zA-Z0-9-]+}.foobar.com`) && PathPrefix(`/bar`)",
							Service: "testing-service1-80",
						},
					},
					Services: map[string]*dynamic.Service{
						"testing-service1-80": {
							LoadBalancer: &dynamic.ServersLoadBalancer{
								Strategy:       dynamic.BalancerStrategyWRR,
								PassHostHeader: pointer(true),
								ResponseForwarding: &dynamic.ResponseForwarding{
									FlushInterval: ptypes.Duration(100 * time.Millisecond),
								},
								Servers: []dynamic.Server{
									{
										URL:    "http://10.10.0.1:8080",
										Scheme: "",
										Port:   "",
									},
								},
							},
						},
					},
				},
			},
		},
		{
			desc: "Ingress with multiple ingressClasses",
			expected: &dynamic.Configuration{
				HTTP: &dynamic.HTTPConfiguration{
					Middlewares: map[string]*dynamic.Middleware{},
					Routers: map[string]*dynamic.Router{
						"testing-foo": {
							Rule:    "PathPrefix(`/foo`)",
							Service: "testing-service1-80",
						},
						"testing-bar": {
							Rule:    "PathPrefix(`/bar`)",
							Service: "testing-service1-80",
						},
					},
					Services: map[string]*dynamic.Service{
						"testing-service1-80": {
							LoadBalancer: &dynamic.ServersLoadBalancer{
								Strategy:       dynamic.BalancerStrategyWRR,
								PassHostHeader: pointer(true),
								ResponseForwarding: &dynamic.ResponseForwarding{
									FlushInterval: ptypes.Duration(100 * time.Millisecond),
								},
								Servers: []dynamic.Server{
									{
										URL: "http://10.10.0.1:8080",
									},
								},
							},
						},
					},
				},
			},
		},
		{
			desc:         "Ingress with ingressClasses filter",
			ingressClass: "traefik-lb2",
			expected: &dynamic.Configuration{
				HTTP: &dynamic.HTTPConfiguration{
					Middlewares: map[string]*dynamic.Middleware{},
					Routers: map[string]*dynamic.Router{
						"testing-foo": {
							Rule:    "PathPrefix(`/foo`)",
							Service: "testing-service1-80",
						},
					},
					Services: map[string]*dynamic.Service{
						"testing-service1-80": {
							LoadBalancer: &dynamic.ServersLoadBalancer{
								Strategy:       dynamic.BalancerStrategyWRR,
								PassHostHeader: pointer(true),
								ResponseForwarding: &dynamic.ResponseForwarding{
									FlushInterval: ptypes.Duration(100 * time.Millisecond),
								},
								Servers: []dynamic.Server{
									{
										URL: "http://10.10.0.1:8080",
									},
								},
							},
						},
					},
				},
			},
		},
		{
			desc: "Ingress with prefix pathType",
			expected: &dynamic.Configuration{
				HTTP: &dynamic.HTTPConfiguration{
					Middlewares: map[string]*dynamic.Middleware{},
					Routers: map[string]*dynamic.Router{
						"testing-bar": {
							Rule:    "PathPrefix(`/bar`)",
							Service: "testing-service1-80",
						},
					},
					Services: map[string]*dynamic.Service{
						"testing-service1-80": {
							LoadBalancer: &dynamic.ServersLoadBalancer{
								Strategy:       dynamic.BalancerStrategyWRR,
								PassHostHeader: pointer(true),
								ResponseForwarding: &dynamic.ResponseForwarding{
									FlushInterval: ptypes.Duration(100 * time.Millisecond),
								},
								Servers: []dynamic.Server{
									{
										URL: "http://10.10.0.1:8080",
									},
								},
							},
						},
					},
				},
			},
		},
		{
			desc: "Ingress with empty pathType",
			expected: &dynamic.Configuration{
				HTTP: &dynamic.HTTPConfiguration{
					Middlewares: map[string]*dynamic.Middleware{},
					Routers: map[string]*dynamic.Router{
						"testing-bar": {
							Rule:    "Path(`/bar`)",
							Service: "testing-service1-80",
						},
					},
					Services: map[string]*dynamic.Service{
						"testing-service1-80": {
							LoadBalancer: &dynamic.ServersLoadBalancer{
								Strategy:       dynamic.BalancerStrategyWRR,
								PassHostHeader: pointer(true),
								ResponseForwarding: &dynamic.ResponseForwarding{
									FlushInterval: ptypes.Duration(100 * time.Millisecond),
								},
								Servers: []dynamic.Server{
									{
										URL: "http://10.10.0.1:8080",
									},
								},
							},
						},
					},
				},
			},
		},
		{
			desc: "Ingress with exact pathType",
			expected: &dynamic.Configuration{
				HTTP: &dynamic.HTTPConfiguration{
					Middlewares: map[string]*dynamic.Middleware{},
					Routers: map[string]*dynamic.Router{
						"testing-bar": {
							Rule:    "Path(`/bar`)",
							Service: "testing-service1-80",
						},
					},
					Services: map[string]*dynamic.Service{
						"testing-service1-80": {
							LoadBalancer: &dynamic.ServersLoadBalancer{
								Strategy:       dynamic.BalancerStrategyWRR,
								PassHostHeader: pointer(true),
								ResponseForwarding: &dynamic.ResponseForwarding{
									FlushInterval: ptypes.Duration(100 * time.Millisecond),
								},
								Servers: []dynamic.Server{
									{
										URL: "http://10.10.0.1:8080",
									},
								},
							},
						},
					},
				},
			},
		},
		{
			desc: "Ingress with implementationSpecific pathType",
			expected: &dynamic.Configuration{
				HTTP: &dynamic.HTTPConfiguration{
					Middlewares: map[string]*dynamic.Middleware{},
					Routers: map[string]*dynamic.Router{
						"testing-bar": {
							Rule:    "Path(`/bar`)",
							Service: "testing-service1-80",
						},
					},
					Services: map[string]*dynamic.Service{
						"testing-service1-80": {
							LoadBalancer: &dynamic.ServersLoadBalancer{
								Strategy:       dynamic.BalancerStrategyWRR,
								PassHostHeader: pointer(true),
								ResponseForwarding: &dynamic.ResponseForwarding{
									FlushInterval: ptypes.Duration(100 * time.Millisecond),
								},
								Servers: []dynamic.Server{
									{
										URL: "http://10.10.0.1:8080",
									},
								},
							},
						},
					},
				},
			},
		},
		{
			desc: "Ingress with ingress annotation",
			expected: &dynamic.Configuration{
				HTTP: &dynamic.HTTPConfiguration{
					Middlewares: map[string]*dynamic.Middleware{},
					Routers: map[string]*dynamic.Router{
						"testing-bar": {
							Rule:    "PathPrefix(`/bar`)",
							Service: "testing-service1-80",
						},
					},
					Services: map[string]*dynamic.Service{
						"testing-service1-80": {
							LoadBalancer: &dynamic.ServersLoadBalancer{
								Strategy:       dynamic.BalancerStrategyWRR,
								PassHostHeader: pointer(true),
								ResponseForwarding: &dynamic.ResponseForwarding{
									FlushInterval: ptypes.Duration(100 * time.Millisecond),
								},
								Servers: []dynamic.Server{
									{
										URL: "http://10.10.0.1:8080",
									},
								},
							},
						},
					},
				},
			},
		},
		{
			// Duplicate test case with the same fixture as the one above, but with the disableIngressClassLookup option to true.
			// Showing that disabling the ingressClass discovery still allow the discovery of ingresses with ingress annotation.
			desc:                      "Ingress with ingress annotation",
			disableIngressClassLookup: true,
			expected: &dynamic.Configuration{
				HTTP: &dynamic.HTTPConfiguration{
					Middlewares: map[string]*dynamic.Middleware{},
					Routers: map[string]*dynamic.Router{
						"testing-bar": {
							Rule:    "PathPrefix(`/bar`)",
							Service: "testing-service1-80",
						},
					},
					Services: map[string]*dynamic.Service{
						"testing-service1-80": {
							LoadBalancer: &dynamic.ServersLoadBalancer{
								Strategy:       dynamic.BalancerStrategyWRR,
								PassHostHeader: pointer(true),
								ResponseForwarding: &dynamic.ResponseForwarding{
									FlushInterval: ptypes.Duration(100 * time.Millisecond),
								},
								Servers: []dynamic.Server{
									{
										URL: "http://10.10.0.1:8080",
									},
								},
							},
						},
					},
				},
			},
		},
		{
			// Duplicate test case with the same fixture as the one above, but with the disableClusterScopeResources option to true.
			// Showing that disabling the ingressClass discovery still allow the discovery of ingresses with ingress annotation.
			desc:                         "Ingress with ingress annotation",
			disableClusterScopeResources: true,
			expected: &dynamic.Configuration{
				HTTP: &dynamic.HTTPConfiguration{
					Middlewares: map[string]*dynamic.Middleware{},
					Routers: map[string]*dynamic.Router{
						"testing-bar": {
							Rule:    "PathPrefix(`/bar`)",
							Service: "testing-service1-80",
						},
					},
					Services: map[string]*dynamic.Service{
						"testing-service1-80": {
							LoadBalancer: &dynamic.ServersLoadBalancer{
								Strategy:       dynamic.BalancerStrategyWRR,
								PassHostHeader: pointer(true),
								ResponseForwarding: &dynamic.ResponseForwarding{
									FlushInterval: ptypes.Duration(100 * time.Millisecond),
								},
								Servers: []dynamic.Server{
									{
										URL: "http://10.10.0.1:8080",
									},
								},
							},
						},
					},
				},
			},
		},
		{
			desc: "Ingress with ingressClass",
			expected: &dynamic.Configuration{
				HTTP: &dynamic.HTTPConfiguration{
					Middlewares: map[string]*dynamic.Middleware{},
					Routers: map[string]*dynamic.Router{
						"testing-bar": {
							Rule:    "PathPrefix(`/bar`)",
							Service: "testing-service1-80",
						},
					},
					Services: map[string]*dynamic.Service{
						"testing-service1-80": {
							LoadBalancer: &dynamic.ServersLoadBalancer{
								Strategy:       dynamic.BalancerStrategyWRR,
								PassHostHeader: pointer(true),
								ResponseForwarding: &dynamic.ResponseForwarding{
									FlushInterval: ptypes.Duration(100 * time.Millisecond),
								},
								Servers: []dynamic.Server{
									{
										URL: "http://10.10.0.1:8080",
									},
								},
							},
						},
					},
				},
			},
		},
		{
			// Duplicate test case with the same fixture as the one above, but with the disableIngressClassLookup option to true.
			// Showing that disabling the ingressClass discovery avoid discovering Ingresses with an IngressClass.
			desc:                      "Ingress with ingressClass",
			disableIngressClassLookup: true,
			expected: &dynamic.Configuration{
				HTTP: &dynamic.HTTPConfiguration{
					Middlewares: map[string]*dynamic.Middleware{},
					Routers:     map[string]*dynamic.Router{},
					Services:    map[string]*dynamic.Service{},
				},
			},
		},
		{
			// Duplicate test case with the same fixture as the one above, but with the disableClusterScopeResources option to true.
			// Showing that disabling the ingressClass discovery avoid discovering Ingresses with an IngressClass.
			desc:                         "Ingress with ingressClass",
			disableClusterScopeResources: true,
			expected: &dynamic.Configuration{
				HTTP: &dynamic.HTTPConfiguration{
					Middlewares: map[string]*dynamic.Middleware{},
					Routers:     map[string]*dynamic.Router{},
					Services:    map[string]*dynamic.Service{},
				},
			},
		},
		{
			desc: "Ingress with named port",
			expected: &dynamic.Configuration{
				HTTP: &dynamic.HTTPConfiguration{
					Middlewares: map[string]*dynamic.Middleware{},
					Routers: map[string]*dynamic.Router{
						"testing-bar": {
							Rule:    "PathPrefix(`/bar`)",
							Service: "testing-service1-foobar",
						},
					},
					Services: map[string]*dynamic.Service{
						"testing-service1-foobar": {
							LoadBalancer: &dynamic.ServersLoadBalancer{
								Strategy:       dynamic.BalancerStrategyWRR,
								PassHostHeader: pointer(true),
								ResponseForwarding: &dynamic.ResponseForwarding{
									FlushInterval: ptypes.Duration(100 * time.Millisecond),
								},
								Servers: []dynamic.Server{
									{
										URL: "http://10.10.0.1:4711",
									},
								},
							},
						},
					},
				},
			},
		},
		{
			desc: "Ingress with missing ingressClass",
			expected: &dynamic.Configuration{
				HTTP: &dynamic.HTTPConfiguration{
					Middlewares: map[string]*dynamic.Middleware{},
					Routers:     map[string]*dynamic.Router{},
					Services:    map[string]*dynamic.Service{},
				},
			},
		},
		{
			desc: "Ingress with defaultbackend",
			expected: &dynamic.Configuration{
				HTTP: &dynamic.HTTPConfiguration{
					Middlewares: map[string]*dynamic.Middleware{},
					Routers: map[string]*dynamic.Router{
						"default-router": {
							Rule:       "PathPrefix(`/`)",
							RuleSyntax: "default",
							Priority:   math.MinInt32,
							Service:    "default-backend",
						},
					},
					Services: map[string]*dynamic.Service{
						"default-backend": {
							LoadBalancer: &dynamic.ServersLoadBalancer{
								Strategy:       dynamic.BalancerStrategyWRR,
								PassHostHeader: pointer(true),
								ResponseForwarding: &dynamic.ResponseForwarding{
									FlushInterval: ptypes.Duration(100 * time.Millisecond),
								},
								Servers: []dynamic.Server{
									{
										URL: "http://10.10.0.1:8080",
									},
								},
							},
						},
					},
				},
			},
		},
		{
			desc: "Ingress with endpoint conditions",
			expected: &dynamic.Configuration{
				HTTP: &dynamic.HTTPConfiguration{
					Middlewares: map[string]*dynamic.Middleware{},
					Routers: map[string]*dynamic.Router{
						"testing-bar": {
							Rule:    "PathPrefix(`/bar`)",
							Service: "testing-service1-80",
						},
					},
					Services: map[string]*dynamic.Service{
						"testing-service1-80": {
							LoadBalancer: &dynamic.ServersLoadBalancer{
								Strategy:       dynamic.BalancerStrategyWRR,
								PassHostHeader: pointer(true),
								ResponseForwarding: &dynamic.ResponseForwarding{
									FlushInterval: ptypes.Duration(100 * time.Millisecond),
								},
								Servers: []dynamic.Server{
									{
										URL: "http://10.10.0.1:8080",
									},
									{
										URL: "http://10.10.0.2:8080",
									},
									{
										URL:    "http://10.10.0.3:8080",
										Fenced: true,
									},
									{
										URL:    "http://10.10.0.4:8080",
										Fenced: true,
									},
								},
							},
						},
					},
				},
			},
		},
		{
			desc: "Ingress with strict prefix matching",
			expected: &dynamic.Configuration{
				HTTP: &dynamic.HTTPConfiguration{
					Middlewares: map[string]*dynamic.Middleware{},
					Routers: map[string]*dynamic.Router{
						"testing-bar": {
							Rule:    "(Path(`/bar`) || PathPrefix(`/bar/`))",
							Service: "testing-service1-80",
						},
					},
					Services: map[string]*dynamic.Service{
						"testing-service1-80": {
							LoadBalancer: &dynamic.ServersLoadBalancer{
								Strategy:       dynamic.BalancerStrategyWRR,
								PassHostHeader: pointer(true),
								ResponseForwarding: &dynamic.ResponseForwarding{
									FlushInterval: ptypes.Duration(100 * time.Millisecond),
								},
								Servers: []dynamic.Server{
									{
										URL: "http://10.10.0.1:8080",
									},
									{
										URL: "http://10.21.0.1:8080",
									},
								},
							},
						},
					},
				},
			},
			strictPrefixMatching: true,
		},
	}

	for _, test := range testCases {
		t.Run(test.desc, func(t *testing.T) {
			t.Parallel()

			clientMock := newClientMock(generateTestFilename(test.desc))
			p := Provider{
				IngressClass:                 test.ingressClass,
				AllowEmptyServices:           test.allowEmptyServices,
				DisableIngressClassLookup:    test.disableIngressClassLookup,
				DisableClusterScopeResources: test.disableClusterScopeResources,
				DefaultRuleSyntax:            test.defaultRuleSyntax,
				StrictPrefixMatching:         test.strictPrefixMatching,
			}
			conf := p.loadConfigurationFromIngresses(t.Context(), clientMock)

			assert.Equal(t, test.expected, conf)
		})
	}
}

func TestLoadConfigurationFromIngressesWithExternalNameServices(t *testing.T) {
	testCases := []struct {
		desc                      string
		ingressClass              string
		allowExternalNameServices bool
		expected                  *dynamic.Configuration
	}{
		{
			desc: "Ingress with service with externalName",
			expected: &dynamic.Configuration{
				HTTP: &dynamic.HTTPConfiguration{
					Middlewares: map[string]*dynamic.Middleware{},
					Routers:     map[string]*dynamic.Router{},
					Services:    map[string]*dynamic.Service{},
				},
			},
		},
		{
			desc:                      "Ingress with service with externalName enabled",
			allowExternalNameServices: true,
			expected: &dynamic.Configuration{
				HTTP: &dynamic.HTTPConfiguration{
					Middlewares: map[string]*dynamic.Middleware{},
					Routers: map[string]*dynamic.Router{
						"testing-traefik-tchouk-bar": {
							Rule:    "Host(`traefik.tchouk`) && PathPrefix(`/bar`)",
							Service: "testing-service1-8080",
						},
					},
					Services: map[string]*dynamic.Service{
						"testing-service1-8080": {
							LoadBalancer: &dynamic.ServersLoadBalancer{
								Strategy:       dynamic.BalancerStrategyWRR,
								PassHostHeader: pointer(true),
								ResponseForwarding: &dynamic.ResponseForwarding{
									FlushInterval: ptypes.Duration(100 * time.Millisecond),
								},
								Servers: []dynamic.Server{
									{
										URL: "http://traefik.wtf:8080",
									},
								},
							},
						},
					},
				},
			},
		},
		{
			desc: "Ingress with IPv6 endpoints",
			expected: &dynamic.Configuration{
				HTTP: &dynamic.HTTPConfiguration{
					Middlewares: map[string]*dynamic.Middleware{},
					Routers: map[string]*dynamic.Router{
						"testing-example-com-bar": {
							Rule:    "PathPrefix(`/bar`)",
							Service: "testing-service-bar-8080",
						},
					},
					Services: map[string]*dynamic.Service{
						"testing-service-bar-8080": {
							LoadBalancer: &dynamic.ServersLoadBalancer{
								Strategy: dynamic.BalancerStrategyWRR,
								Servers: []dynamic.Server{
									{
										URL: "http://[2001:0db8:3c4d:0015:0000:0000:1a2f:1a2b]:8080",
									},
								},
								PassHostHeader: pointer(true),
								ResponseForwarding: &dynamic.ResponseForwarding{
									FlushInterval: ptypes.Duration(100 * time.Millisecond),
								},
							},
						},
					},
				},
			},
		},
		{
			desc:                      "Ingress with IPv6 endpoints externalname enabled",
			allowExternalNameServices: true,
			expected: &dynamic.Configuration{
				HTTP: &dynamic.HTTPConfiguration{
					Middlewares: map[string]*dynamic.Middleware{},
					Routers: map[string]*dynamic.Router{
						"testing-example-com-foo": {
							Rule:    "PathPrefix(`/foo`)",
							Service: "testing-service-foo-8080",
						},
					},
					Services: map[string]*dynamic.Service{
						"testing-service-foo-8080": {
							LoadBalancer: &dynamic.ServersLoadBalancer{
								Strategy: dynamic.BalancerStrategyWRR,
								Servers: []dynamic.Server{
									{
										URL: "http://[2001:0db8:3c4d:0015:0000:0000:1a2f:2a3b]:8080",
									},
								},
								PassHostHeader: pointer(true),
								ResponseForwarding: &dynamic.ResponseForwarding{
									FlushInterval: ptypes.Duration(100 * time.Millisecond),
								},
							},
						},
					},
				},
			},
		},
	}

	for _, test := range testCases {
		t.Run(test.desc, func(t *testing.T) {
			t.Parallel()

			clientMock := newClientMock(generateTestFilename(test.desc))

			p := Provider{IngressClass: test.ingressClass}
			p.AllowExternalNameServices = test.allowExternalNameServices
			conf := p.loadConfigurationFromIngresses(t.Context(), clientMock)

			assert.Equal(t, test.expected, conf)
		})
	}
}

func TestLoadConfigurationFromIngressesWithNativeLB(t *testing.T) {
	testCases := []struct {
		desc         string
		ingressClass string
		expected     *dynamic.Configuration
	}{
		{
			desc: "Ingress with native service lb",
			expected: &dynamic.Configuration{
				HTTP: &dynamic.HTTPConfiguration{
					Middlewares: map[string]*dynamic.Middleware{},
					Routers: map[string]*dynamic.Router{
						"testing-traefik-tchouk-bar": {
							Rule:    "Host(`traefik.tchouk`) && PathPrefix(`/bar`)",
							Service: "testing-service1-8080",
						},
					},
					Services: map[string]*dynamic.Service{
						"testing-service1-8080": {
							LoadBalancer: &dynamic.ServersLoadBalancer{
								Strategy:           dynamic.BalancerStrategyWRR,
								ResponseForwarding: &dynamic.ResponseForwarding{FlushInterval: dynamic.DefaultFlushInterval},
								PassHostHeader:     pointer(true),
								Servers: []dynamic.Server{
									{
										URL: "http://10.0.0.1:8080",
									},
								},
							},
						},
					},
				},
			},
		},
	}

	for _, test := range testCases {
		t.Run(test.desc, func(t *testing.T) {
			t.Parallel()

			clientMock := newClientMock(generateTestFilename(test.desc))

			p := Provider{IngressClass: test.ingressClass}
			conf := p.loadConfigurationFromIngresses(t.Context(), clientMock)

			assert.Equal(t, test.expected, conf)
		})
	}
}

func TestLoadConfigurationFromIngressesWithNodePortLB(t *testing.T) {
	testCases := []struct {
		desc                 string
		clusterScopeDisabled bool
		expected             *dynamic.Configuration
	}{
		{
			desc: "Ingress with node port lb",
			expected: &dynamic.Configuration{
				HTTP: &dynamic.HTTPConfiguration{
					Middlewares: map[string]*dynamic.Middleware{},
					Routers: map[string]*dynamic.Router{
						"testing-traefik-tchouk-bar": {
							Rule:    "Host(`traefik.tchouk`) && PathPrefix(`/bar`)",
							Service: "testing-service1-8080",
						},
					},
					Services: map[string]*dynamic.Service{
						"testing-service1-8080": {
							LoadBalancer: &dynamic.ServersLoadBalancer{
								Strategy:           dynamic.BalancerStrategyWRR,
								ResponseForwarding: &dynamic.ResponseForwarding{FlushInterval: dynamic.DefaultFlushInterval},
								PassHostHeader:     pointer(true),
								Servers: []dynamic.Server{
									{
										URL: "http://172.16.4.4:32456",
									},
								},
							},
						},
					},
				},
			},
		},
		{
			desc:                 "Ingress with node port lb cluster scope disabled",
			clusterScopeDisabled: true,
			expected: &dynamic.Configuration{
				HTTP: &dynamic.HTTPConfiguration{
					Middlewares: map[string]*dynamic.Middleware{},
					Routers:     map[string]*dynamic.Router{},
					Services:    map[string]*dynamic.Service{},
				},
			},
		},
	}

	for _, test := range testCases {
		t.Run(test.desc, func(t *testing.T) {
			t.Parallel()

			clientMock := newClientMock(generateTestFilename(test.desc))

			p := Provider{DisableClusterScopeResources: test.clusterScopeDisabled}
			conf := p.loadConfigurationFromIngresses(t.Context(), clientMock)

			assert.Equal(t, test.expected, conf)
		})
	}
}

func generateTestFilename(desc string) string {
	return filepath.Join("fixtures", strings.ReplaceAll(desc, " ", "-")+".yml")
}

func TestGetCertificates(t *testing.T) {
	testIngressWithoutHostname := buildIngress(
		iNamespace("testing"),
		iRules(
			iRule(iHost("ep1.example.com")),
			iRule(iHost("ep2.example.com")),
		),
		iTLSes(
			iTLS("test-secret"),
		),
	)

	testIngressWithoutSecret := buildIngress(
		iNamespace("testing"),
		iRules(
			iRule(iHost("ep1.example.com")),
		),
		iTLSes(
			iTLS("", "foo.com"),
		),
	)

	testCases := []struct {
		desc      string
		ingress   *netv1.Ingress
		client    Client
		result    map[string]*tls.CertAndStores
		errResult string
	}{
		{
			desc:    "api client returns error",
			ingress: testIngressWithoutHostname,
			client: clientMock{
				apiSecretError: errors.New("api secret error"),
			},
			errResult: "failed to fetch secret testing/test-secret: api secret error",
		},
		{
			desc:      "api client doesn't find secret",
			ingress:   testIngressWithoutHostname,
			client:    clientMock{},
			errResult: "secret testing/test-secret does not exist",
		},
		{
			desc:    "entry 'tls.crt' in secret missing",
			ingress: testIngressWithoutHostname,
			client: clientMock{
				secrets: []*corev1.Secret{
					{
						ObjectMeta: metav1.ObjectMeta{
							Name:      "test-secret",
							Namespace: "testing",
						},
						Data: map[string][]byte{
							"tls.key": []byte("tls-key"),
						},
					},
				},
			},
			errResult: "secret testing/test-secret is missing the following TLS data entries: tls.crt",
		},
		{
			desc:    "entry 'tls.key' in secret missing",
			ingress: testIngressWithoutHostname,
			client: clientMock{
				secrets: []*corev1.Secret{
					{
						ObjectMeta: metav1.ObjectMeta{
							Name:      "test-secret",
							Namespace: "testing",
						},
						Data: map[string][]byte{
							"tls.crt": []byte("tls-crt"),
						},
					},
				},
			},
			errResult: "secret testing/test-secret is missing the following TLS data entries: tls.key",
		},
		{
			desc:    "secret doesn't provide any of the required fields",
			ingress: testIngressWithoutHostname,
			client: clientMock{
				secrets: []*corev1.Secret{
					{
						ObjectMeta: metav1.ObjectMeta{
							Name:      "test-secret",
							Namespace: "testing",
						},
						Data: map[string][]byte{},
					},
				},
			},
			errResult: "secret testing/test-secret is missing the following TLS data entries: tls.crt, tls.key",
		},
		{
			desc: "add certificates to the configuration",
			ingress: buildIngress(
				iNamespace("testing"),
				iRules(
					iRule(iHost("ep1.example.com")),
					iRule(iHost("ep2.example.com")),
					iRule(iHost("ep3.example.com")),
				),
				iTLSes(
					iTLS("test-secret"),
					iTLS("test-secret2"),
				),
			),
			client: clientMock{
				secrets: []*corev1.Secret{
					{
						ObjectMeta: metav1.ObjectMeta{
							Name:      "test-secret2",
							Namespace: "testing",
						},
						Data: map[string][]byte{
							"tls.crt": []byte("tls-crt"),
							"tls.key": []byte("tls-key"),
						},
					},
					{
						ObjectMeta: metav1.ObjectMeta{
							Name:      "test-secret",
							Namespace: "testing",
						},
						Data: map[string][]byte{
							"tls.crt": []byte("tls-crt"),
							"tls.key": []byte("tls-key"),
						},
					},
				},
			},
			result: map[string]*tls.CertAndStores{
				"testing-test-secret": {
					Certificate: tls.Certificate{
						CertFile: types.FileOrContent("tls-crt"),
						KeyFile:  types.FileOrContent("tls-key"),
					},
				},
				"testing-test-secret2": {
					Certificate: tls.Certificate{
						CertFile: types.FileOrContent("tls-crt"),
						KeyFile:  types.FileOrContent("tls-key"),
					},
				},
			},
		},
		{
			desc:    "return nil when no secret is defined",
			ingress: testIngressWithoutSecret,
			client:  clientMock{},
			result:  map[string]*tls.CertAndStores{},
		},
	}

	for _, test := range testCases {
		t.Run(test.desc, func(t *testing.T) {
			t.Parallel()

			tlsConfigs := map[string]*tls.CertAndStores{}
			err := getCertificates(t.Context(), test.ingress, test.client, tlsConfigs)

			if test.errResult != "" {
				assert.EqualError(t, err, test.errResult)
			} else {
				assert.NoError(t, err)
				assert.Equal(t, test.result, tlsConfigs)
			}
		})
	}
}

func TestLoadConfigurationFromIngressesWithNativeLBByDefault(t *testing.T) {
	testCases := []struct {
		desc         string
		ingressClass string
		expected     *dynamic.Configuration
	}{
		{
			desc: "Ingress with native service lb",
			expected: &dynamic.Configuration{
				HTTP: &dynamic.HTTPConfiguration{
					Middlewares: map[string]*dynamic.Middleware{},
					Routers: map[string]*dynamic.Router{
						"testing-traefik-tchouk-bar": {
							Rule:    "Host(`traefik.tchouk`) && PathPrefix(`/bar`)",
							Service: "testing-service1-8080",
						},
					},
					Services: map[string]*dynamic.Service{
						"testing-service1-8080": {
							LoadBalancer: &dynamic.ServersLoadBalancer{
								Strategy:           dynamic.BalancerStrategyWRR,
								ResponseForwarding: &dynamic.ResponseForwarding{FlushInterval: dynamic.DefaultFlushInterval},
								PassHostHeader:     pointer(true),
								Servers: []dynamic.Server{
									{
										URL: "http://10.0.0.1:8080",
									},
								},
							},
						},
					},
				},
			},
		},
		{
			desc: "Ingress with native lb by default",
			expected: &dynamic.Configuration{
				HTTP: &dynamic.HTTPConfiguration{
					Middlewares: map[string]*dynamic.Middleware{},
					Routers: map[string]*dynamic.Router{
						"default-global-native-lb-traefik-tchouk-bar": {
							Rule:    "Host(`traefik.tchouk`) && PathPrefix(`/bar`)",
							Service: "default-service1-8080",
						},
					},
					Services: map[string]*dynamic.Service{
						"default-service1-8080": {
							LoadBalancer: &dynamic.ServersLoadBalancer{
								Strategy:           dynamic.BalancerStrategyWRR,
								ResponseForwarding: &dynamic.ResponseForwarding{FlushInterval: dynamic.DefaultFlushInterval},
								PassHostHeader:     pointer(true),
								Servers: []dynamic.Server{
									{
										URL: "http://10.0.0.1:8080",
									},
								},
							},
						},
					},
				},
			},
		},
		{
			desc: "Ingress with native lb by default but service has disabled nativelb",
			expected: &dynamic.Configuration{
				HTTP: &dynamic.HTTPConfiguration{
					Middlewares: map[string]*dynamic.Middleware{},
					Routers: map[string]*dynamic.Router{
						"default-global-native-lb-traefik-tchouk-bar": {
							Rule:    "Host(`traefik.tchouk`) && PathPrefix(`/bar`)",
							Service: "default-native-disabled-svc-web",
						},
					},
					Services: map[string]*dynamic.Service{
						"default-native-disabled-svc-web": {
							LoadBalancer: &dynamic.ServersLoadBalancer{
								Strategy:           dynamic.BalancerStrategyWRR,
								ResponseForwarding: &dynamic.ResponseForwarding{FlushInterval: dynamic.DefaultFlushInterval},
								PassHostHeader:     pointer(true),
								Servers: []dynamic.Server{
									{
										URL: "http://10.10.0.20:8080",
									},
									{
										URL: "http://10.10.0.21:8080",
									},
								},
							},
						},
					},
				},
			},
		},
	}

	for _, test := range testCases {
		t.Run(test.desc, func(t *testing.T) {
			t.Parallel()

			clientMock := newClientMock(generateTestFilename(test.desc))

			p := Provider{
				IngressClass:      test.ingressClass,
				NativeLBByDefault: true,
			}
			conf := p.loadConfigurationFromIngresses(t.Context(), clientMock)

			assert.Equal(t, test.expected, conf)
		})
	}
}

func TestIngressEndpointPublishedService(t *testing.T) {
	testCases := []struct {
		desc                         string
		disableClusterScopeResources bool
		expected                     []netv1.IngressLoadBalancerIngress
	}{
		{
			desc: "Published Service ClusterIP",
			expected: []netv1.IngressLoadBalancerIngress{
				{
					IP: "1.2.3.4",
					Ports: []netv1.IngressPortStatus{
						{Port: 9090, Protocol: "TCP"},
						{Port: 9091, Protocol: "TCP"},
					},
				},
				{
					IP: "5.6.7.8",
					Ports: []netv1.IngressPortStatus{
						{Port: 9090, Protocol: "TCP"},
						{Port: 9091, Protocol: "TCP"},
					},
				},
			},
		},
		{
			desc: "Published Service LoadBalancer",
			expected: []netv1.IngressLoadBalancerIngress{
				{
					IP: "1.2.3.4",
					Ports: []netv1.IngressPortStatus{
						{Port: 9090, Protocol: "TCP"},
						{Port: 9091, Protocol: "TCP"},
					},
				},
				{
					IP: "5.6.7.8",
					Ports: []netv1.IngressPortStatus{
						{Port: 9090, Protocol: "TCP"},
						{Port: 9091, Protocol: "TCP"},
					},
				},
			},
		},
		{
			desc:                         "Published Service NodePort",
			disableClusterScopeResources: true,
		},
		{
			desc: "Published Service NodePort",
			expected: []netv1.IngressLoadBalancerIngress{
				{
					IP: "1.2.3.4",
					Ports: []netv1.IngressPortStatus{
						{Port: 9090, Protocol: "TCP"},
						{Port: 9091, Protocol: "TCP"},
					},
				},
				{
					IP: "5.6.7.8",
					Ports: []netv1.IngressPortStatus{
						{Port: 9090, Protocol: "TCP"},
						{Port: 9091, Protocol: "TCP"},
					},
				},
			},
		},
		{
			desc: "Published Service ExternalName",
			expected: []netv1.IngressLoadBalancerIngress{
				{
					Hostname: "example.com",
				},
			},
		},
	}

	for _, test := range testCases {
		t.Run(test.desc, func(t *testing.T) {
			t.Parallel()

			k8sObjects := readResources(t, []string{generateTestFilename(test.desc)})
			kubeClient := kubefake.NewClientset(k8sObjects...)

			client := newClientImpl(kubeClient)

			stopCh := make(chan struct{})
			eventCh, err := client.WatchAll(nil, stopCh)
			require.NoError(t, err)

			if k8sObjects != nil {
				// just wait for the first event
				<-eventCh
			}

			p := Provider{
				DisableClusterScopeResources: test.disableClusterScopeResources,
				IngressEndpoint: &EndpointIngress{
					PublishedService: "default/published-service",
				},
			}
			p.loadConfigurationFromIngresses(t.Context(), client)

			ingress, err := kubeClient.NetworkingV1().Ingresses(metav1.NamespaceDefault).Get(t.Context(), "foo", metav1.GetOptions{})
			require.NoError(t, err)

			assert.Equal(t, test.expected, ingress.Status.LoadBalancer.Ingress)
		})
	}
}

func readResources(t *testing.T, paths []string) []runtime.Object {
	t.Helper()

	var k8sObjects []runtime.Object
	for _, path := range paths {
		yamlContent, err := os.ReadFile(filepath.FromSlash(path))
		if err != nil {
			panic(err)
		}

		objects := k8s.MustParseYaml(yamlContent)
		k8sObjects = append(k8sObjects, objects...)
	}

	return k8sObjects
}

func TestStrictPrefixMatchingRule(t *testing.T) {
	tests := []struct {
		path        string
		requestPath string
		match       bool
	}{ // The tests are taken from https://kubernetes.io/docs/concepts/services-networking/ingress/#examples
		{
			path:        "/foo",
			requestPath: "/foo",
			match:       true,
		},
		{
			path:        "/foo",
			requestPath: "/foo/",
			match:       true,
		},
		{
			path:        "/foo/",
			requestPath: "/foo",
			match:       true,
		},
		{
			path:        "/foo/",
			requestPath: "/foo/",
			match:       true,
		},
		{
			path:        "/aaa/bb",
			requestPath: "/aaa/bbb",
			match:       false,
		},
		{
			path:        "/aaa/bbb",
			requestPath: "/aaa/bbb",
			match:       true,
		},
		{
			path:        "/aaa/bbb/",
			requestPath: "/aaa/bbb",
			match:       true,
		},
		{
			path:        "/aaa/bbb",
			requestPath: "/aaa/bbb/",
			match:       true,
		},
		{
			path:        "/aaa/bbb",
			requestPath: "/aaa/bbb/ccc",
			match:       true,
		},
		{
			path:        "/aaa/bbb",
			requestPath: "/aaa/bbbxyz",
			match:       false,
		},
		{
			path:        "/",
			requestPath: "/aaa/ccc",
			match:       true,
		},
		{
			path:        "/aaa",
			requestPath: "/aaa/ccc",
			match:       true,
		},
		{
			path:        "/...",
			requestPath: "/aaa",
			match:       false,
		},
		{
			path:        "/...",
			requestPath: "/.../",
			match:       true,
		},
	}

	for _, tt := range tests {
		t.Run(fmt.Sprintf("Prefix match case %s", tt.path), func(t *testing.T) {
			t.Parallel()

			handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
			parser, err := traefikhttp.NewSyntaxParser()
			require.NoError(t, err)

			muxer := traefikhttp.NewMuxer(parser)

			rule := buildStrictPrefixMatchingRule(tt.path)
			err = muxer.AddRoute(rule, "", 0, handler)
			require.NoError(t, err)

			w := httptest.NewRecorder()
			req := httptest.NewRequest(http.MethodGet, tt.requestPath, http.NoBody)
			muxer.ServeHTTP(w, req)

			if tt.match {
				assert.Equal(t, http.StatusOK, w.Code)
			} else {
				assert.Equal(t, http.StatusNotFound, w.Code)
			}
		})
	}
}
